\subsection{Visualisierung}

\subsubsection{Aufgaben}
Die wichtigste Aufgabe sämtlicher in der Anwendung des Edubot Systems verbauten Visualisierungen ist es, den Betrieb der Software auch ohne angeschlossene Hardware zu ermöglichen. Ein wichtiger Nebenaspekt der Visualisierung ist jedoch auch die Möglichkeit zu geben, bei angeschlossener Hardware die vom Roboter getätigten Verfahrbewegungen kontrollieren zu können.
Letztere Funktion der Visualisierung kam vor allem bei der Entwicklung der Software für die Ansteuerung des Edubot Modells, sowie bei der Entwicklung der verschiedenen Interpolationsarten sehr intensiv zum Einsatz. 

\subsubsection{Allgemeines und Aufbau}
Für die Edubot Anwendung stehen im Allgemeinen zwei Arten der Visualisierung bereit, einerseits eine Maßstabsgetreue Simulation des Edubot Modells, andererseits eine universelle, schematische Darstellung Simulation eines Roboters mit RR Kinematik. 
Die Simulation des Edubot Modells kann in den Einstellungen nach belieben ein oder ausgeschaltet werden und kann nur mit den Achsverhältnissen des Edubot Modells betrieben werden. Für diese Simulation kann nur eine 3D Ansicht gewählt werden.
Die universelle Robotersimulation ist immer vorhanden und passt sich automatisch den eingegebenen Achsrelationen an. Für diese Simulation gibt es sowohl eine 3D Ansicht, als auch eine zweidimensionsale Darstellung in Form einer Ansicht von oben.

\begin{figure}[H]
  \centering
  \begin{minipage}[t]{12 cm}
  	\centering
  	\includegraphics[width=12cm]{images/3DModels} 
    \caption{Visualisierungs-Modelle}
  \end{minipage}
\end{figure} 

Bei der Erstellung der Visualisierungen wurde jeweils zuvor ein dreidimensionales Modell in Google SketchUp angefertigt. Dieses Modell wurde durch Google SketchUp in Form einer .obj Datei exportiert und später mithilfe von Microsoft Expression Blend konvertiert. In Visual Studio wurde das Modell schließlich als UserControll implementiert und mit der nötigen Programmlogik zur Animaton versehen.
Die einzelnen Schritte werden in den nächsten Kapiteln genauer beschrieben.
\subsubsection{Anfertigung und Vorbereitung der Modelle}
Wie bereits erwähnt wurden die 3D Modelle zuerst im Programm SketchUp angefertigt. Dies ist mithilfe der von Google zur Verfügung gestellten Software bereits nach kurzer Einarbeitungszeit möglich. 
Prinzipiell basiert die Erstellung von 3D Modellen in SketchUp auf dem Prinzip, zuerst Flächen zu zeichnen und diese dann mit einem Entsprechenden Tool zu einem Körper auseinander zu "'ziehen"'.

Das fertige Modell des Roboters wurde im nächsten Schritt als "'.obj"' Datei gespeichert. Beim "'.obj"' Dateityp handelt es sich um einen von der Firma Wavefront entwickelten offenen Dateityp zur Speicherung von 3D Modellen. Das dreidimmensionsale Objekt wird dabei in seine einzelnen Formen aufgeteilt und in Form von einzelnen Koordinatennetzen die sich als normaler Text in in der Datei finden gespeichert.

Der große Vorteil der Speicherung als "'.obj"' Datei ist die vielfältige Wiederverwendbarkeit des Modells. So ist es etwa möglich, das Modell mithilfe der Software Microsoft Expression Blend zu öffnen und für die Verwendung in WPF entsprechend zu konvertieren. Die entsprechende "'.obj"' muss hierzu lediglich auf die Arbeitsfläche des XAML Designers eines WPF Projektes gezogen werden. Microsoft Expression Blend übernimmt dann alle Vorgänge die zur Umrechnung nötig sind und bettet das 3D Modell in die XAML Datei ein. 
Sämtliche Informationen zur Geometrie des Modells werden dabei in der XAML Datei gespeichert und die einzelnen Komponenten werden jeweils als \textit{GeometryModel3D} Elemente erzeugt.
Jedes dieser Elemente enthält nun in Form der Koordinatennetze eine einzelnes Objekt des 3D Modells. Um die einzelnen Objekte, bei denen es sich um um minimale Einzelteile wie beispielsweise eine Einzelne Motrwelle handelt, später nicht alle Einzeln im Programmcode ansprechen zu müssen, wurden Objekte bei der Erstellung des Modells zu Komponenten zusammengefasst. Diese Komponenten können beispielsweise eine gesamte achse mit Gelenk oder ähnliches darstellen und sind im XAML Dokument als \textit{ModelVisual3D}, welches seinerseits mehrere \textit{GeometryModel3D} Elemente enthält, definiert.
Als Übergeordnetes Element für das gesamte 3D Modell dient ein \textit{ViewPort3d} Modell dass die einzelnen Komponenten Enthält und zusätzlich über ein \textit{PerspectiveCamera} Element den Blickwinkel und verschiedene Beleuchtungsoptionen definiert.

Das eben beschriebene \textit{ViewPort3D} Überelement kann nun aus der, durch Expression Blend erstellten, XAML Datei kopiert und in eine beliebige XAML Datei in einem Visual Studio WPF Projekt eingefügt werden. Im Fall der Edubot Anwendung wurde die Visualisierung als UserControll programmiert um das einfache Einfügen an beliebigen Punkten zu ermöglichen. Aus diesem Grund wurde das \textit{Viewport3d} Objekt in XAML Datei des UserControlls eingefügt.

\subsubsection{Allgemeine Programmierung der Animation}
Wie im vorherigen Unterkapitel bereits erwähnt wurden die einzelnen Simulationen jeweils als UserControls ausgegliedert und später in die Hauptanwendung integriert. 
In WPF besteht ein UserControl immer aus zwei verschiedenen Dateien, einer XAML Datei als Markup des Designs und einer seperaten C\# Codedatei welche die Logik hinter dem UserControl bereitstellt. Die XAML Datei wurde bereits im vorhergehenden Kapitel in ihren Grobzügen erklärt, wissenswert ist an dieser Stelle noch dass bei einem UserControl das Element auf der untersten Ebene ein Element vom Typ \textit{UserControl}, darüber liegt standardmäßig ein Element vom Typ \textit{Grid} welches die Anordnung der Unterlemente (in unserem Fall direkt das zuvor Erzeugte \textit{ViewPort3D} Element) ähnlich wie bei einer Tabelle in HTML ermöglicht.

Auf die in der XAML Datei definierten Elemente kann, sofern ihnen über das \textit{name} Attribut zugewiesen wurde, aus dem Programmcode zugegriffen werden. Dieser befindet sich in der zweiten zum UserControl gehörenden Datei.

In der beschriebenen Code Datei befindet sich nun die eigentlich für die Animation benötigte Code Date. 

Für die Animation werden die in der API berrechneten Interpolationsergebnisse benötigt. Dazu besitzt der für die Visualierung verwendete Adapter einen Event (\textit{OnMovementStarted}) der eine ihm zugewewiesen Methode in der Anwendung benachrichtigt wenn neue Interpolationsergebnisse zur Verfügung stehen und diese auch gleich dieser Methode übergibt. 

Um auch die Visualisierung des Homings zu ermöglichen und desweiteren einen Abbruch der Simulation zu ermöglichen, enthält jedes UserControl entsprechende Methoden mit den Namen \textit{Home} und \textit{Abort}. Diese werden bei den entsprechenden Events \textit{OnHoming} und \textit{OnAbort} aufgerufen. Die eigentliche Animation wird allerdings von der \textit{Move}-Methode ausgeführt. Jede der soeben angeführten Methoden wird bei Ankunft der Benachrichtigung in einem eigenen Thread gestartet um die Oberfläche während der Ausführung nicht zu blockieren.

\begin{lstlisting}[language=CSharp, caption={Ausschnitt aus der Move-Methode der 2D-Visualisierung}, captionpos=b]
foreach (InterpolationStep step in result.Angles)
                {
                    ticks = MAX_SPEED + 1 - (((float)MAX_SPEED / 100) * configuration.Speed);       
                    currentPath.End = step.Target;
                    System.Threading.Thread.Sleep((int)ticks);
                    Dispatcher.Invoke(updatePrimaryAngle, step.Alpha1);
                    Dispatcher.Invoke(updateSecondaryAngle, step.Alpha2);
                    Dispatcher.Invoke(new Action(delegate { InvalidateVisual(); }));
                }
\end{lstlisting}

Die \textit{Move}-Methode führt in einer Schleife alle im Interpolationsergebnis enthaltenen Schritte (Teilstrecken) hintereinander aus und verschiebt die Achsen um den jeweiligen Winkel beziehungsweise um die jeweilige Strecke. 

Da es sich bei den Achsen um Objekte des ursprünglichen Threads handelt, muss für den Zugriff darauf ein Dispatcher verwendet werden. Der Zugriff mittels eines Dispatchers ermöglicht das Aufrufen einzelner Delegaten welche Methoden aufrufen die ihrerseits dann die Werte verändern, die Veränderung der Werte geschieht im urspünglichen Thread und das Dispatcher Objekt stellt eine Art Warteschlange dar. An dieser Stelle wird jedoch nicht genauer auf diesen Mechanismus eingegangen, da dies den Rahmen dieser Arbeit sprengen würde.

Das Rotieren und Verschieben der Roboterachsen kann über das WPF eigene \textit{Tranform3DGroup} Objekt, sowie über das \textit{Transform} Property der im XAML definierten \textit{ModelVisual3D} Elemente.
Hierzu wird im Code ein Objekt vom Typ \textit{ Transform3DGroup} angelegt. Diesem Objekt enthält eine Liste der die durchzuführenden Transformationen angefügt werden können. Für die verschiedenen Transformationsarten stellt WPF jeweils Klassen bereit die das Interface \textit{Transform3D} implentiert. Für unsere Animation wurden folgende Transformationsarten verwendet:

\begin{itemize}
\item \textbf{RotateTransform3D}\\
Durch ein Objekt dieser Klasse wird eine Rotation definiert. Beim Anlegen eines Objektes dieses Klasse muss ein Objekt vom Typ \textit{AxisAngleRotation3D} mitgegeben, welches speziell eine rotatorische Transformation um eine einzelne Achse definiert und über ein \textit{Vector3D} Objekt die Informationen über die Lage der Achse um die rotiert werden soll erhält. Zusätzlich müssen für das \textit{AxisAngleRotation3D} Objekt noch der zu Rotierende Winkel und optional falls nicht der Koordinatenursprung verwendet werden soll ein Mittelpunkt für die Rotation gewählt werden.

\item \textbf{ScaleTransform3D}\\
Ein Objekt der Klasse \textbf{ScaleTransform3D} defiert die Skalierung die bei seiner Anwendung auf ein Element angewendet wird. Um die Skalierung genau zu definieren muss ein Mittelpunkt (bei nicht Angabe Koordinatenursprung) mittels der Übergabe eines \textit{Point3D} Objektes definiert werden. Zusätzlich muss ein \textit{Vector3D} Objekt übergeben werden welches die eigentliche Skalierung entlang der Achsen, ausgehend vom Mittelpunkt definiert.

\item \textbf{TranslateTransform3D}\\
Durch Hinzufügen eines Objektes dieser Klasse zu einer \\textit{TransformGroup3D} wird das Element auf dass diese angewendet wird verschoben. Zur Definition wie diese Verschiebung durchgeführt werden soll wird dem \textit{TranslateTransform3D} Objekt ein \textit{Vector3D} Objekt übergeben in dem für jede Achse die Distanz um die verschoben werden soll angegeben wird.
\end{itemize}

Wurden die benötigten Transformationen in Form der beschriebenen Objekte dem \textit{ Transform3DGroup} Objekt angehängt, so kann dieses nun dem zu transformierenden Element aus der XAML Datei übergeben werden. Dies geschieht durch einfaches Zuweisen des \textit{ Transform3DGroup} Objektes an das \textit{ Transform} Property zu Transformierenden XAML Elements. Wie erwähnt handelt es sich dabei in unserem Fall um ein Objet des Typs \textit{ModelVisual3D} durch dass jeweils eine Komponente des Modells dargestellt wird.

Die \textit{Home}-Methode bedient sich derselben Arbeitsweise wie die \textit{Move}-Methode. Jedoch wird hier statt eines Interpolationsergebnisses, ein Korrekturwinkel mitgegeben. Innerhalb einer Schleife werden die Winkel der Achsen nun solange um den Korrekturwinkel geändert bis beide auf 0 $^\circ$ stehen. Die Abweichung von diesem Wert beträgt in jedem Fall weniger als der mitgegebene Korrekturwinkel.

Die \textit{Abort}-Methode hat die simple Aufgabe, den aktuellen Animations-Thread zu beenden, falls ein solcher vorhanden ist. Dazu wird die \textit{Abort}-Methode der Thread-Klasse verwendet. Um in Sonderfällen keine \textit{ThreadAbortException} zu verursachen, ist über die gesamte \textit{Move}- beziehungsweise \textit{Home}-Methode ein \textit{try-catch}-Block gelegt, der diese Exception abfängt.

Es existieren ebenfalls Methoden für die Events \textit{OnShuttingDown} und \textit{OnToolUsed}, welche jedoch keine essentiellen Funktionen die Animation betreffend ausführen und deshalb auch nicht näher im schriftlichen Teil dieser Diplomarbeit erläutert werden.

\begin{lstlisting}[language=CSharp, caption={Ausschnitt aus der ApplyConfiguration-Methode der 2D-Visualisierung}, captionpos=b]
if (property.PropertyName == "VisualizationEnabled")
            {
                if (configuration.VisualizationEnabled)
                {
                    visualisationAdapter = new VirtualAdapter(Tool.VIRTUAL, configuration.Length, configuration.Length2);
                    visualisationAdapter.OnAbort += StopAnimation;
                    visualisationAdapter.OnMovementStarted += StartMoving;
                    visualisationAdapter.OnHoming += StartHoming;
                    visualisationAdapter.OnToolUsed += UseTool;
                    visualisationAdapter.OnShuttingDown += Shutdown;
                    API.Edubot.GetInstance().RegisterAdapter("2DVisualization", visualisationAdapter);
                }
                else
                {
                    if (visualisationAdapter != null)
                    {
                        visualisationAdapter.OnAbort -= StopAnimation;
                        visualisationAdapter.OnMovementStarted -= StartMoving;
                        visualisationAdapter.OnHoming -= StartHoming;
                        visualisationAdapter.OnToolUsed -= UseTool;
                        visualisationAdapter.OnShuttingDown -= Shutdown;
                        API.Edubot.GetInstance().DeregisterAdapter("2DVisualization");
                    }
                }
            }
\end{lstlisting}

Da der Großteil der Aktionen die in einer der Visualisierungen durchgeführt werden, von den Visualisierungs-Einstellungen abhängen, besitzt jede Visualisierung eine \textit{ApplyConfiguration}-Methode. Diese wird aufgerufen sobald sich ein Property bei den Einstellungen ändert, um entsprechend darauf zu reagieren. Wird beispielsweise die Visualisierung eingeschaltet, so wird ein entsprechender VirtualAdapter mit den Werten aus dem \textit{VisualizationConfig}-Objekt erzeugt und bei der \textit{Edubot}-Klasse registriert. Weiters werden die \textit{Home}-, \textit{Move}- und \textit{Abort}-Methoden bei den entsprechenden Events des erzeugten Adapters eingetragen.

\subsubsection{Programmierung der 2D-Animation}

Neben den oben angeführten Funktionen, sollte die 2D-Version erweiterte Darstellungs- und Animationsmöglichkeiten bieten. Dazu gehört das Anzeigen eines Koordinationsystems mit entsprechender Beschriftung, sowie das Einzeichnen des gefahrenen Pfades.

Dazu wurde die \textit{OnRender}-Methode des UserControls überschrieben in der neben dem eigentlichen Rendern des UserContols noch zusätzliche eigene Zeichenvorgänge durchgeführt werden.
Die Logik hinter den \textit{RenderGrid} und \textit{RenderLabels}-Methoden wird hier nicht detaillierter beschrieben, da sie mit Hilfe des Source-Codes relativ einfach nachvollzogen werden können.

\begin{lstlisting}[language=CSharp, caption={Ausschnitt aus der RenderPath-Methode der 2D-Visualisierung}, captionpos=b]
for(int i = drawnPaths.Count-1; i >= 0; i--){
                path = drawnPaths.ElementAt(i);
                if (path.Type == InterpolationType.Circular)
                {
                    DrawArc(drawingContext, null, path.Dashed ? dashedPen : pen, new Point(center + path.Start.X * pixelPerPoint, center - path.Start.Y * pixelPerPoint), new Point(center + path.End.X * pixelPerPoint, center - path.End.Y * pixelPerPoint),(float) (path.Radius * pixelPerPoint), path.Direction);
                }
                else
                {
                    if (path.Type == InterpolationType.Linear)
                    {
                        drawingContext.DrawLine(path.Dashed ? dashedPen : pen, new Point(center + path.Start.X * pixelPerPoint, center - path.Start.Y * pixelPerPoint), new Point(center + path.End.X * pixelPerPoint, center - path.End.Y * pixelPerPoint));
                    }
                }
            }
\end{lstlisting}

Etwas komplexer gestaltet sich jedoch die \textit{RenderPath}-Methode, welche den bisher gefahrenen Pfad des Roboters darstellt. Dazu wird in einer Schleife eine Collection aus \textit{Path}-Objekten und diese mit Hilfe der enthaltenen Informationen eingezeichnet. Die Collection enthält lediglich Pfade die bereits abgefahren wurden. Der aktuelle Pfad ist in der \textit{currentPath}-Variable gespeichert und wird beim Durchlaufen des Interpolationergebnisses regelmäßig aktualisiert. Erst wenn die aktuelle Bewegung abgeschlossen wurde, wird das \textit{currentPath}-Objekt der Collection hinzugefügt.

Ein \textit{Path}-Objekt enthält detaillierte Information über Position und Typ des abgefahrenen Pfades. Dazu enthält es folgende Properties:
\begin{itemize}
\item \textbf{Start}\\
Dabei handelt es sich um ein \textit{Point3D}-Objekt, welches den Startpunkt des Pfades enthält.
\item \textbf{End}\\
Dabei handelt es sich um ein \textit{Point3D}-Objekt, welches den Endpunkt des Pfades enthält.
\item \textbf{Type}\\
Das \textit{Type}-Property enthält Informationen darüber ob es sich bei dem Pfad um einen zirkularen oder einen linearen Pfad handelt. Durch diese Information kann der Render-Prozess wesentlich beschleunigt werden, da dadurch nicht einzelne Pfadpunkte sondern gleich der ganze Pfad gezeichnet werden kann.
Je nach wird in der \textit{RenderPath}-Methode die \textit{DrawLine} oder die \textit{DrawArc}-Methode zum Zeichnen aufgerufen.
\item \textbf{Dashed}\\
Dieser Wert vom Typ Boolean definiert ob der Pfad strichliert oder durchgehend eingezeichnet werden soll. Ist das Werkzeug des Roboters gerade eingeschaltet so wird der Pfad durchgehend gezeichnet, andernfalls strichliert.
\item \textbf{Direction}\\
Diese Information ist nur bei zirkularen Bewegungen nötig und gibt an in welche Richtung der entsprechende Kreisbogen gezeichnet wird. Der Wert dieses Properties wird im \textit{MetaData}-Objekt des Interpolationergebnisses mitgegebenen.
\item \textbf{Radius}\\
Auch diese Information ist im \textit{MetaData}-Objekt des Interpolationergebnisses enthalten und dient zur Verbesserung der Performance des Systems, da dadurch der Radius der Kreisbewegung nicht erneut berechnet werden muss.

\end{itemize}
